package com.ny.zmb.openapi.ysutil.utils;


import com.ny.zmb.openapi.ysutil.base.BaseHeadReqCommand;

import java.io.*;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

/**
 * <P>API签名/签验工具/参数构建</P>
 * 
 * @version $Id$
 * @user linxl 2018年2月22日 下午3:26:24
 */
public class YsMpPayUtils {

	// 字符编码
	public static final String CHARSET = "utf-8";
	// 签名方式
	public static final String SIGN_TYPE = "RSA";
	// 签名值
	public static final String SIGN_INFO = "sign";
	private final static String ALGORITHM = "SHA1WithRSA";

	// 签名方式
	public static final String SIGN_TYPE_RSA = "RSA";

	// 生产

	public final static String YS_VALIDY_SIGN_PUBLIC_CER = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7SPkmIUf2auwkgbVchMyfeCDgICuA1GKrSwRbDI24UMVhzDgcIxCUmFG5/DfcPJz0d3oV9Ggkd4/7NmteRvmNnOOGNOnmR6AGEKafDpL1mAdpndmpkAZ0f6OVo3Py5JDg2wt8d+u3dF0AFWwd2rrrqscWvxJVB55DnuZfXl2CyQIDAQAB";

	public static String txt2String(String fileName) {
		StringBuilder result = new StringBuilder();
		try {
			// 构造一个BufferedReader类来读取文件
			// BufferedReader br = new BufferedReader(new FileReader(file));
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8"));
			String s = null;
			// 使用readLine方法，一次读一行
			while ((s = br.readLine()) != null) {
				result.append(System.lineSeparator() + s);
			}
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result.toString();
	}

	public static void main(String[] args) {
		try {
			String result = "{\"00\":\"000\",\"rrr\":\"0rrr00\"}";

			Map<String, String> map = new HashMap();
			map.put("msg", "网关参数错误:serviceNo[请求参数最长长度为:50,当前参数值为:value=null]");
			map.put("code", "SYS005");
			map.put("requestId", "be895e96e3b7432286b8d1815ca34b1d");
			Map<String, String> ma2p = new HashMap();
			ma2p.put("fileCode", "");
			ma2p.put("subCode", "COM003");
			ma2p.put("subMsg", "业务失败:图片写入异常");
			// map.put("bizResponseJson", JsonParser.toJson(ma2p));

			// String parserJavaObjectToJsonString = JsonParser1.parserJavaObjectToJsonString(ma2p,
			// false);
			// System.out.println("==========" + parserJavaObjectToJsonString);

			// String tt =
			// "{\"msg\":\"网关处理成功\",\"code\":\"SYS000\",\"requestId\":\"61a3203113d846c58f8f07ce2477d184\",\"bizResponseJson\":\"{\\\"accountDate\\\":\\\"\\\",\\\"buyerId\\\":\\\"\\\",\\\"channelRecvNo\\\":\\\"\\\",\\\"channelSendNo\\\":\\\"\\\",\\\"merchantOrderNo\\\":\\\"\\\",\\\"payTime\\\":\\\"\\\",\\\"payerInfo\\\":\\\"\\\",\\\"settleAmount\\\":\\\"\\\",\\\"status\\\":\\\"fail\\\",\\\"statusMeg\\\":\\\"系统中已经存在相同订单号的业务(业务类型不一致)\\\",\\\"ysTradeNo\\\":\\\"\\\"}\"}";

			// Map<String, String> objectToMap = JsonParser1.toMap(tt);
			// map.put("bizResponseJson",
			// "{\"fileCode\":\"\",\"subCode\":\"COM003\",\"subMsg\":\"业务失败:图片写入异常\"}");

			// Map<String, String> rstMap = JsonParser.toMap(result);
			// rstMap.put("sign",
			// "fPxho467yUefsEbtKmrTZEuMzAPYYiNE9l+3JF+QWnaqW5tErNPoLVq/GSRhniDdSzcT0GtmCXsea4FMOZ8mPdrSyy1UDtPCe/7Pff9JoE69Rs5j9wyX8Afsd5neyaRmeqGtlJejhBFHc/DV5QxNz9agS0IRqVKnDmaOfuzTXFI=");
			map.put("sign",
					"R959cgo3iSTWVGLcLPd7GnFzwKIBVaC0QW+d3UXSdM10ga79fIGS/sl00MiiudrpokD/BvugvfGpUJsEZMP1E+kKmDYG7aiqbtY64J+58jOotIwEjAsKGhp8Y/7RVf/owD1861k3IzQIrSyb2sP7jm+9UstI3rlXCrcRobQNSI4=");
			boolean verifySign = verifySign(map, YS_VALIDY_SIGN_PUBLIC_CER);
			System.out.println("==================" + verifySign);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * <p>验证签名</p>
	 * 
	 * @user linxl 2020年11月27日 上午11:32:20
	 */
	public static boolean verifySign(String publicCerPath, Map<String, String> responseMap, boolean isShowLog) {
		File file = new File(publicCerPath);
		boolean isSign = false;
		try {
			InputStream is = new FileInputStream(file);
			isSign = SignUtils.rsaCheckContent(is, responseMap, responseMap.get(SIGN_INFO), CHARSET, publicCerPath,
					isShowLog);
		} catch (Exception e) {
			throw new RuntimeException("验证签名失败，请检查银盛公钥证书文件是否存在[" + publicCerPath + "]");
		}
		return isSign;
	}

	/**
	 * RSA验签名检查
	 * 
	 * @param content 待签名数据
	 * @param sign 签名值
	 * @param publicKey 分配给开发商公钥
	 * @param encode 字符集编码
	 * @return 布尔值
	 * @throws YsChannelClientException
	 */
	public static boolean verifySign(Map<String, String> rstMap, String publicKey) throws YsChannelClientException {
		try {
			String content = StringUtils.createLinkString(SignUtils.paraFilter(rstMap));
			System.out.println("======>" + content);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			byte[] encodedKey = Base64Utils.decode(publicKey);
			PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
			java.security.Signature signature = java.security.Signature.getInstance(ALGORITHM);
			signature.initVerify(pubKey);
			signature.update(content.getBytes());
			return signature.verify(Base64Utils.decode(rstMap.get(SIGN_INFO)));
		} catch (Exception e) {
			e.printStackTrace();
			throw new YsChannelClientException("CHANNEL_VERIFY_SIGN_FAIL", "验证签名异常");
		}
	}

	// 响应结果包含签名
	public static Map<String, String> buildResponseSign(String privateCerPwd, String privateCerPath,
                                                        BaseHeadReqCommand baseReqCommand) throws YsChannelClientException {
		Map<String, String> reqHeadMap = JsonParser.ObjectToMap(baseReqCommand);
		// 除去数组中的空值和签名参数
		Map<String, String> sPara = SignUtils.paraFilter(reqHeadMap);
		String bizJson = "";
		if("uploadDocument".equals(baseReqCommand.getServiceNo())){
			bizJson = sPara.get("bizReqJson");
			sPara.remove("bizReqJson");
		}
		/* 通过file读取证书 */
		File file = new File(privateCerPath);
		try {
			InputStream pfxCertFileInputStream = new FileInputStream(file);
			// 遍历以及根据重新排序
			String signContent = SignUtils.getSignContent(sPara);
			String sign = SignUtils.rsaSign(signContent,
					reqHeadMap.get("charset") == null ? "UTF-8" : reqHeadMap.get("charset"), privateCerPwd,
					pfxCertFileInputStream, privateCerPath);
			sPara.put("sign", sign);
			if("uploadDocument".equals(baseReqCommand.getServiceNo())){
				sPara.put("bizReqJson", bizJson);
			}
			return sPara;
		} catch (Exception e) {
			throw new YsChannelClientException("CHANNEL_SIGN_FAIL", "签名失败，请检查证书文件是否存在，密码是否正确");
		}
	}

	// 响应结果包含签名
	public static Map<String, String> buildResponseSign(String privateCerPwd, String privateCerPath,
                                                        Map<String, String> reqHeadMap) throws YsChannelClientException {
		System.out.println("reqHeadMap==" + reqHeadMap);
		// 除去数组中的空值和签名参数
		Map<String, String> sPara = SignUtils.paraFilter(reqHeadMap);
		System.out.println("sPara==" + sPara);
		/* 通过file读取证书 */
		File file = new File(privateCerPath);
		try {
			InputStream pfxCertFileInputStream = new FileInputStream(file);
			// 遍历以及根据重新排序
			String signContent = SignUtils.getSignContent(sPara);

			System.out.println("signContent==" + signContent);

			String sign = SignUtils.rsaSign(signContent,
					reqHeadMap.get("charset") == null ? "UTF-8" : reqHeadMap.get("charset"), privateCerPwd,
					pfxCertFileInputStream, privateCerPath);
			sPara.put("sign", sign);
			return sPara;
		} catch (Exception e) {
			throw new YsChannelClientException("CHANNEL_SIGN_FAIL", "签名失败，请检查证书文件是否存在，密码是否正确");
		}
	}

	/**
	 * <p>支付请求响应内容</p>
	 * 
	 * @param payResponse
	 * @return Map<String,String>
	 * @user linxl 2018年2月22日 下午2:50:27
	 */
	private static Map<String, String> builderContent(String payResponse) {
		Map<String, String> sParaTemp = JsonParser.toMap(payResponse);
		List<String> keys = new ArrayList<String>(sParaTemp.keySet());
		// Collections.sort(keys);
		Map<String, String> result = new TreeMap<String, String>();
		if (keys == null || keys.size() <= 0) {
			throw new NullPointerException("支付请求响应内容为空");
		}
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = sParaTemp.get(key);
			if (value == null || StringUtils.isEmpty(value) || key.equalsIgnoreCase(SIGN_INFO)) {
				continue;
			}
			result.put(key, value);
		}
		return result;
	}

	/**
	 * <p>验证签名</p>
	 * 
	 * @param publicCerPath
	 * @param sign
	 * @param responseBody
	 * @param charset
	 * @return boolean
	 * @user linxl 2018年2月22日 下午3:28:08
	 */
	private static boolean verifyJsonSign(String publicCerPath, String sign, String responseBody, String charset) {
		File file = new File(publicCerPath);
		boolean isSign = false;
		try {
			InputStream is = new FileInputStream(file);
			isSign = SignUtils.rsaCheckContent(is, responseBody, sign, charset, publicCerPath);
		} catch (Exception e) {
			throw new RuntimeException("验证签名失败，请检查银盛公钥证书文件是否存在[" + publicCerPath + "]");
		}
		return isSign;
	}
}
